#include "StdAfx.h"
#include "Parser.h"
#include <iostream>
#include <fstream>
#include <sstream>

Parser::Parser() {
	error = "";
	nroLinea = 1;
}


void Parser::setError(string linea, string err) {

	string nroLineaString;
	stringstream out;
	out << nroLinea;
	nroLineaString = out.str();

	error = "** Error de Parseo: La estructura del XML no es valida. \n\n"
			+err+
			":\n\n" + nroLineaString + ": <" + linea+">";

	//cerr<<error<<"\n\n";


}

string Parser::leerlinea(ifstream &arch) {
	string linea = "";

	char c = '\0';

	while ((c != '<')&&(!arch.eof())) 
	{
		c = arch.get();
		
		if (c== '\n') nroLinea++;
	}


	while ((c != '>')&&(!arch.eof())) {
		c = arch.get();
		
		if (c!= '>') linea += c;

		if (c== '\n') nroLinea++;
	}


	return linea;
}


void Parser::skip(ifstream &arch, string hasta) {
	string avance = "";
						
	while (!arch.eof()) {
		avance = leerlinea(arch);

		// Preparo un stream para operaciones sobre el tag
		stringstream sstravance(avance);
		
		// Obtengo el nombre
		string tag;
		sstravance >> tag;

		tag	= tag.substr(1);

		if (tag.compare(hasta) == 0) {
			break;
		} 	
	}

}

// devuelve 0 si esta todo bien, 1 si es un error no fatal, 2 si es un error fatal.
int Parser::interpretacionRecursiva(ifstream &arch, NodoXML &nodo, string tagCierre, string linea, int nivel) {

		// Preparo un stream para operaciones sobre el tag
		stringstream ss(linea);
		string lineaSinEspacios;
		
		// Obtengo el nombre
		string nombre;
		ss >> nombre;

		nodo.nombre = nombre;

		string buffer;
		// Paso el resto del stream a una linea sin espacios
		while (ss >> buffer) {
			lineaSinEspacios += buffer;
		}


		int cant = 0;
		for (int j = 0 ; j<lineaSinEspacios.length(); j++) {
			char c = lineaSinEspacios[j];

			if (c == '\"') {
				cant++;
			}
		}

		if (cant%2 != 0) {
			setError(linea,"Falta una \" en la linea");
			skip(arch,nodo.nombre);
			return 1;
		}

		/*
		int j=0;
		int k=0;
		int cant = 0;
		while (j != string::npos) {
			j = lineaSinEspacios.find('\"',k);
			if (j != string::npos) {
				cant++;
			}

			k=j;
		}*/

		int i = 0;
		int n = 0;

		while ((i != string::npos)&&(lineaSinEspacios.size()>0)) {
			i = lineaSinEspacios.find('=',n);

			if (i != string::npos) {
				string nomAtr = lineaSinEspacios.substr(n,i-n);
				n = i+2;

				int d = lineaSinEspacios.find('\"',n);
				

				if (lineaSinEspacios.length()<i) {
					// Se esperaba encontrar mas cosas despues del =
					setError(linea,"Fin inesperado de la linea");
					skip(arch,nodo.nombre);
					return 1;
				}

				if (lineaSinEspacios[i+1] != '\"') {
					// Deberia haber un " de apertura
					setError(linea,"Se esperaba un \" de apertura");
					skip(arch,nodo.nombre);
					return 1;
				}

				if (d == string::npos) {
					//No se encontro el " de cierre
					setError(linea,"Se esperaba un \" de cierre");
					skip(arch,nodo.nombre);
					return 1;
				}

				string valAtr = lineaSinEspacios.substr(n,d-n);

				n = d+1;
				
				nodo.addAttribute(nomAtr,valAtr);

			}
		}

		char ultimoCaracter;

		if (lineaSinEspacios.size()>0)
			ultimoCaracter = lineaSinEspacios[lineaSinEspacios.length()-1];

		if (ultimoCaracter == '/' ) {
			// Es un nodo hoja, no tiene hijos
			return 0;

		} else {
			// Es un nodo con hijos
			
			while (!arch.eof()) {
				string proxlinea = leerlinea(arch);

				// Preparo un stream para operaciones sobre el tag
				stringstream sstr(proxlinea);
		
				// Obtengo el nombre
				string nomTag;
				sstr >> nomTag;

				if (nomTag[0] != '/') {
					
					NodoXML hijo;
					int proxNivel = nivel+1;
					
					
					int err = 0;

					//Llamado recursivo enviandole como nodo el hijo
					try {
						err = interpretacionRecursiva(arch,hijo,nodo.nombre,proxlinea,proxNivel);
					}
					catch(int e) {
						nodo.addChild(hijo);	
						//throw e;
					}

					if (err !=1) {
						nodo.addChild(hijo);	
					} 
					
						
				} else {

					nomTag = nomTag.substr(1);

					if (nomTag.compare(nodo.nombre) == 0) {
						break;
					} else 
					{
						//string sms = "Se llego a un tag de cierre <" +nomTag+ "> sin hallarse el cierre del tag <" + nodo.nombre + ">.\nProbablemente falte el tag de cierre en la linea";
						//Log4Cpp::error(sms.c_str(), "Parser.cpp");
						setError(linea,"Se llego a un tag de cierre <"+nomTag+"> sin hallarse el cierre del tag <"+nodo.nombre+">.\nProbablemente falte el tag de cierre en la linea");
						throw 2;
					}
				}

			}

		}

		return 0;
}

int Parser::parsear(char* ruta){

	ifstream arch;

	arch.open(ruta,ios::in);

	if (arch.is_open()) {

		string linea = leerlinea(arch);		
		
		try {
			interpretacionRecursiva(arch,arbolXML,"",linea,0);		
		} catch (int e) {
			throw e;
		}

	} else {
		cerr<<"Error: No se pudo abrir el archivo.\n\n";
	}

	arch.close();


	return 0;
}
